﻿using IGeekFan.AspNetCore.Knife4jUI;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Models;
using SqlSugar;
using System.IO;

namespace SimpleX
{
    public static partial class ServicesExtension
    {
        public static IServiceCollection AddSwagger(this IServiceCollection services)
        {
            var swaggerSetting = App.Get<SwaggerSettings>("Swagger");

            if (swaggerSetting.Enabled)
            {
                services.AddSwaggerGen(options =>
                {
                    //分组
                    var groupNames = GetEffectiveApiExplorerSettingsAttributeNames();
                    foreach (var item in groupNames)
                    {
                        var docname = swaggerSetting.DocNames?.FirstOrDefault(x => x.Name == item);
                        if (docname == null && swaggerSetting.ShowWhenDocNamesNotExist)
                            docname = new Docname { Description = $"Swagger:DocNames[{item}] No Description", Name = item };
                        if (docname != null)
                        {
                            options.SwaggerDoc(item, new OpenApiInfo
                            {
                                Title = docname.Name,
                                Description = docname.Description,
                            });
                        }
                    }

                    //排除输出实体部分属性
                    options.SchemaFilter<SwaggerIgnoreSchemaFilter>();

                    //排除输入参数部分属性
                    options.OperationFilter<SwaggerIgnoreOperationFilter>();

                    //设置枚举类型过滤器
                    options.DocumentFilter<SwaggerEnumFilter>();

                    //xml注释
                    var files = Directory.GetFiles(AppContext.BaseDirectory, "*.xml").ToList();
                    files.ForEach(x => options.IncludeXmlComments(x, true));

                    //权限
                    var jwtSettings = App.Get<JwtSettings>("JwtSettings");
                    var security = new Dictionary<string, IEnumerable<string>> { { jwtSettings.Issuer, new string[] { } } };
                    options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme()
                    {
                        Description = "Bearer空格token",
                        Name = "Authorization",
                        In = ParameterLocation.Header,
                        Type = SecuritySchemeType.ApiKey,
                        BearerFormat = "JWT",
                        Scheme = JwtBearerDefaults.AuthenticationScheme
                    });

                    options.AddSecurityRequirement(new OpenApiSecurityRequirement
                    {
                            {
                                new OpenApiSecurityScheme
                                {
                                    Reference = new OpenApiReference {
                                        Type = ReferenceType.SecurityScheme,
                                        Id = "Bearer"
                                    }
                                },
                                new string[] { }
                            }
                    });
                });
            }

            return services;
        }

        public static Microsoft.AspNetCore.Builder.WebApplication UseSwagger(this Microsoft.AspNetCore.Builder.WebApplication @this)
        {
            var swaggerSetting = App.Get<SwaggerSettings>("Swagger");
            if (swaggerSetting.Enabled)
            {
                @this.UseSwagger(c =>
                {
                    c.RouteTemplate = "{documentName}/swagger.json";
                });

                @this.UseKnife4UI(options =>
                {
                    var groupNames = GetEffectiveApiExplorerSettingsAttributeNames();
                    foreach (var item in groupNames)
                    {
                        var docname = swaggerSetting.DocNames?.FirstOrDefault(x => x.Name == item);
                        if (docname == null && swaggerSetting.ShowWhenDocNamesNotExist)
                            docname = new Docname { Name = item };
                        if (docname != null)
                        {
                            options.SwaggerEndpoint($"/{docname.Name}/swagger.json", docname.Name);
                        }
                    }
                    options.RoutePrefix = string.Empty;
                });

                @this.UseSwaggerUI(options =>
                {
                    var groupNames = GetEffectiveApiExplorerSettingsAttributeNames();
                    foreach (var item in groupNames)
                    {
                        var docname = swaggerSetting.DocNames?.FirstOrDefault(x => x.Name == item);
                        if (docname == null && swaggerSetting.ShowWhenDocNamesNotExist)
                            docname = new Docname { Name = item };
                        if (docname != null)
                        {
                            options.SwaggerEndpoint($"/{docname.Name}/swagger.json", docname.Name);
                        }
                    }
                    options.RoutePrefix = "swagger";
                    options.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.None);
                });
            }
            return @this;
        }

        private static List<string> GetEffectiveApiExplorerSettingsAttributeNames()
        {
            var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(ApiExplorerSettingsAttribute), false));
            var apiExplorerSettingsAttributes = entityTypes.Select(x => x.GetCustomAttribute<ApiExplorerSettingsAttribute>());
            return apiExplorerSettingsAttributes.Select(x => x.GroupName).Distinct().ToList();
        }
    }
}